package com.information.manage.basic.common.utils.exportAndImport;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.imports.ExcelImportService;
import com.information.manage.basic.common.utils.exportAndImport.custom.CustomExportExcelStyleOperator;
import com.information.manage.basic.common.utils.exportAndImport.custom.CustomExportExcelTableOperator;
import com.information.manage.basic.common.utils.exportAndImport.custom.ExImportManager;
import com.information.manage.basic.common.utils.exportAndImport.exception.ExImportException;
import com.information.manage.basic.common.utils.exportAndImport.model.SheetDTO;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Created with IntelliJ IDEA.
 * User: Initial Heart
 * Date: 2022-02-03.
 * Description: excel工具类 交由manager管理 不对外提供使用
 * Version: V1.0
 */
public class ExImportExcel {

    /**
     * excel导入
     * @param file 文件
     * @param titleRows
     * @param headerRows
     * @param pojoClass excel对应的类
     * @return
     */
    protected static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
        if (file == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new RuntimeException("excel文件不能为空");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
        return list;
    }

    /**
     * excel导入
     * @param in 输入流
     * @param pojoClass excel对应的类
     * @param params 参数 设置SheetNum、TitleRows、HeadRows等
     * @return
     * @throws Exception
     */
    protected static <T> List<T> importExcel(InputStream in, Class<?> pojoClass, ImportParams params) throws Exception {
        return (new ExcelImportService()).importExcelByIs(in, pojoClass, params, false).getList();
    }

    /**
     * excel导出
     */
    protected static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) {
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    }

    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        if (workbook != null) ;
        downLoadExcel(fileName, response, workbook);
    }

    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-exportAndImport");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 从资源文件中导出模板excel
     * @param response
     * @param path resources下的文件路径
     */
    protected static void downloadExcelTemplate(HttpServletResponse response, String path) {
        InputStream in = ExImportExcel.class.getResourceAsStream(path);
        response.setHeader("content-Type", "application/vnd.ms-exportAndImport");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/octet-stream;charset=UTF-8");
        try {
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("导入模板.xls", "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            System.out.println("设置响应参数错误" + e);
        }
        long fileLength = 0;
        try(OutputStream out = response.getOutputStream()) {
            int count = 0;
            byte[] buffer = new byte[2048];
            ByteArrayOutputStream tempStream = new ByteArrayOutputStream();
            while ((count = in.read(buffer)) != -1){
                tempStream.write(buffer, 0, count);
                fileLength += count;
            }
            response.addHeader("Content-Length", String.valueOf(fileLength));
            out.write(tempStream.toByteArray());
        } catch (IOException e) {
            System.out.println("模板导出错误" + e);
        }
    }

    /**
     * @param clazz 实现不同样式方法的类  自定义样式的class
     * @param sheetNum (sheet的位置，0表示第一个表格中的第一个sheet)
     * @param sheetName （sheet的名称）
     * @param hSSFColor sheet的颜色
     * @param title sheet的标题
     * @param result （表格的数据）
     * @param pojoClass （数据对应的类）
     * @param os 输出流
     */
    protected static void exportExcel(Class clazz, int sheetNum, String sheetName, Short hSSFColor
            , String title, List<?> result, Class<?> pojoClass, OutputStream os){
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
        Field[] declaredFields = pojoClass.getDeclaredFields();
        String[] headers = new String[declaredFields.length];
        handleExcelAnnotation(declaredFields, headers);
        try {
            exportExcel(clazz, xssfWorkbook, sheetNum, sheetName, hSSFColor, title, headers, result);
            xssfWorkbook.write(os);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 处理注解
    private static void handleExcelAnnotation(Field[] declaredFields, String[] headers){
        for (Field declaredField : declaredFields) {
            // 判断是否字段上存在注解  Excel
            boolean annotationPresent = declaredField.isAnnotationPresent(Excel.class);
            if (annotationPresent){
                //获取到注解
                Excel annotation = declaredField.getAnnotation(Excel.class);
                //获取注解的值
                try {
                    Integer value = Integer.valueOf(annotation.orderNum());
                    headers[value] = annotation.name();
                }catch (Exception e){
                    e.printStackTrace();
                    throw new ExImportException("请输入正确的@Excel中orderNum值, 例如orderNum='0' ");
                }
            }
        }
    }

    /**
     * @param clazz 实现不同样式方法的类  自定义样式的class
     * @param workbook
     * @param sheetNum (sheet的位置，0表示第一个表格中的第一个sheet)
     * @param sheetName  （sheet的名称）
     * @param title sheet的标题
     * @param headers    （表格的头行）
     * @param result   （表格的数据）
     * @throws Exception
     */
    private static void exportExcel(Class clazz, XSSFWorkbook workbook, int sheetNum, String sheetName
            , Short hSSFColor, String title, String[] headers, List<?> result) {
        // 生成一个表格
        XSSFSheet sheet = workbook.createSheet();
        workbook.setSheetName(sheetNum, sheetName);
        if (hSSFColor != null) sheet.setTabColor(hSSFColor);
        // 设置表格默认列宽度为20个字节
        sheet.setDefaultColumnWidth((short) 12);
        int index = 0;
        XSSFRow row = sheet.createRow(index);
        // 设置标题
        if (title != null && !"".equals(title)){
            XSSFCellStyle titleStyle = titleStyle(workbook, sheet, 0,0, 0, headers.length-1);
            XSSFCell cell = row.createCell((short) 0);
            cell.setCellStyle(titleStyle);
            HSSFRichTextString text = new HSSFRichTextString(title);
            cell.setCellValue(text.toString());
            //移动到下一行
            row = sheet.createRow(++index);
        }
        // 产生表格头
        for (int i = 0; i < headers.length; i++) {
            XSSFCellStyle style = headerStyle(workbook);
            XSSFCell cell = row.createCell((short) i);
            cell.setCellStyle(style);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text.toString());
        }
        //移动行数
        index++;
        // 遍历集合数据，产生数据行
        if (clazz == null) throw new ExImportException("未实现数据导出样式操作, 导出失败");
        CustomExportExcelStyleOperator operator = ExImportManager.operateStyleMap.get(clazz);
        if (operator == null){
            throw new ExImportException(clazz + "未找到操作器");
        } else {
            operator.functionExcelStyle(result, sheet, workbook, row, index);
        }
    }

    /**
     * 多sheet导出
     * @param sheetDTOList 多个sheet数据
     * @param os 输出流
     */
    protected static void moreSheetExportExcel(List<SheetDTO> sheetDTOList, OutputStream os){
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
        for (SheetDTO sheetDTO : sheetDTOList) {
            Field[] declaredFields = sheetDTO.getPojoClass().getDeclaredFields();
            String[] headers = new String[declaredFields.length];
            handleExcelAnnotation(declaredFields, headers);
            exportExcel(sheetDTO.getClazz(), xssfWorkbook, sheetDTO.getSheetNum(), sheetDTO.getSheetName()
                    , sheetDTO.getHSSFColor(), sheetDTO.getTitle(), headers, sheetDTO.getResult());
        }
        try {
            xssfWorkbook.write(os);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成表格头样式
     * @param workbook
     */
    private static XSSFCellStyle headerStyle(XSSFWorkbook workbook){
        // 生成一个样式
        XSSFCellStyle style = workbook.createCellStyle();
        // 设置这些样式
        style.setFillForegroundColor(HSSFColor.PALE_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 生成一个字体
        XSSFFont font = workbook.createFont();
        font.setColor(HSSFColor.BLACK.index);
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 把字体应用到当前的样式
        style.setFont(font);
        // 指定当单元格内容显示不下时自动换行
        style.setWrapText(true);
        return style;
    }

    /**
     * 生成标题栏样式
     * @param workbook
     * @param sheet
     * @return
     */
    private static XSSFCellStyle titleStyle(XSSFWorkbook workbook, XSSFSheet sheet
            , int firstRow, int lastRow, int firstCol, int lastCol){
        //标题栏样式
        XSSFCellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        titleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); //文字居中
        CellRangeAddress region = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); //合并单元格
        sheet.addMergedRegion(region);
        XSSFFont titleFont = workbook.createFont();
        titleFont.setColor(HSSFColor.BLACK.index);
        titleFont.setFontHeightInPoints((short) 15);
        titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        titleStyle.setFont(titleFont);
        return titleStyle;
    }

    /**
     * 自定义表格样式导出
     * @param clazz 样式类
     * @param os 输出流
     * @param list 数据集
     * @param map 可能用到的其它参数
     */
    protected static void customTableExportExcel(Class clazz, OutputStream os, List<?> list, Map<String, Object> map){
        if (clazz == null) throw new ExImportException("未实现自定义表格操作, 导出失败");
        CustomExportExcelTableOperator operator = ExImportManager.operateTableMap.get(clazz);
        if (operator == null){
            throw new ExImportException(clazz + "未找到自定义表格操作器");
        } else {
            operator.functionExcel(os, list, map);
        }
    }

}
